| 标 志 寄存器 |
BIT31—BIT18 | BIT17 | BIT16 | BIT15 | BIT14 | BIT13—BIT12 | BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
| 00000000000000 | V M |
R F |
0 | N T |
IOPL | OF | D F |
I F |
T F |
S F |
Z F |
0 | A F |
0 | P F |
1 | C F |
| I/O敏感指令 | 指令 | 功能 | 保护方式下的执行条件 |
| CLI | 清除EFLAGS中的IF位 | CPL<=IOPL | |
| STI | 设置EFLAGS中的IF位 | CPL<=IOPL | |
| IN | 从I/O地址读出数据 | CPL<=IOPL或I/O位图许可 | |
| INS | 从I/O地址读出字符串 | CPL<=IOPL或I/O位图许可 | |
| OUT | 向I/O地址写数据 | CPL<=IOPL或I/O位图许可 | |
| OUTS | 向I/O地址写字符串 | CPL<=IOPL或I/O位图许可 |
TSSSEG SEGMENT PARA USE16
TSS <> ;TSS低端固定格式部分
DB 8 DUP(0) ;对应I/O端口00H—3FH
DB 10000000B ;对应I/O端口40H—47H
DB 01100000B ;对用I/O端口48H—4FH
DB 8182 DUP(0ffH) ;对应I/O端口50H—0FFFFH
DB 0FFH ;位图结束字节
TSSLen = $
TSSSEG ENDS
in al,21h ;(1)正常执行
in al,47h ;(2)引起异常
out 20h,al ;(3)正常实行
out 4eh,al ;(4)引起异常
in al,20h ;(5)正常执行
out 20h,eax ;(6)正常执行
out 4ch,ax ;(7)引起异常
in ax,46h ;(8)引起异常
in eax,42h ;(9)正常执行
|
不同特权级对 标志寄存器特 殊字段的处理 |
特权级 | VM标志字段 | IOPL标志字段 | IF标志字段 |
| CPL=0 | 可变(初POPF指令外) | 可变 | 可变 | |
0| 不变 |
不变 |
可变 |
| |
| CPL>IOPL | 不变 | 不变 | 不变 |
;名称:ASM9.ASM
;功能:演示I/O保护及I/O敏感指令的作用
;编译:TASM ASM9.ASM
;连接:TLINK /32 ASM9.OBJ
;----------------------------------------------------------------------------
INCLUDE 386SCD.INC
;----------------------------------------------------------------------------
GDTSeg SEGMENT PARA USE16 ;全局描述符表段(16位)
GDT LABEL BYTE
;空描述符
DUMMY Desc <>
;规范段描述符及选择子
Normal Desc <0ffffh,,,ATDW,,>
Normal_Sel = Normal-GDT
;视频缓冲区段描述符(DPL=3)及选择子(任何特权级可写)
VideoBuf Desc <07fffh,8000h,0bh,ATDW,,>
VideoBuf_Sel = VideoBuf-GDT
;----------------------------------------------------------------------------
EFFGDT LABEL BYTE
;演示任务TSS段描述符及选择子
DemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,>
DemoTSS_Sel = DemoTSS-GDT
;演示任务堆栈段描述符及选择子
DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDW,D32,>
DemoStack_Sel = DemoStack-GDT
;演示代码段描述符及选择子
DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,D32,>
DemoCode_Sel = DemoCode-GDT
;属于演示任务的临时代码段描述符及选择子
TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,>
TempCode_Sel = TempCode-GDT
;指向GDT的存储段描述符及选择子
ToGDT Desc <GDTLen-1,GDTSeg,,ATDW,,>
ToGDT_Sel = ToGDT-GDT
;指向通用保护故障处理任务TSS的存储段描述符及选择子
ToGPTSS Desc <GPTSSLen-1,GPTSSSeg,,ATDW,,>
ToGPTSS_Sel = ToGPTSS-GDT
;指向测试任务TSS的存储段描述符及选择子
ToTestTSS Desc <TestTSSLen-1,TestTSSSeg,,ATDW,,>
ToTestTSS_Sel = ToTestTSS-GDT
;测试任务TSS段描述符及选择子
TestTSS Desc <TestTSSLen-1,TestTSSSeg,,AT386TSS,,>
TestTSS_Sel = TestTSS-GDT
;测试任务1堆栈段描述符(DPL=1)及选择子
Test1Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL1,D32,>
Test1Stack_Sel = Test1Stack-GDT+RPL1
;测试任务1代码段描述符(DPL=1)及选择子
Test1Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL1,D32,>
Test1Code_Sel = Test1Code-GDT+RPL1
;测试任务2堆栈段描述符(DPL=2)及选择子
Test2Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL2,D32,>
Test2Stack_Sel = Test2Stack-GDT+RPL2
;测试任务2代码段描述符(DPL=2)及选择子
Test2Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL2,D32,>
Test2Code_Sel = Test2Code-GDT+RPL2
;测试任务3堆栈段描述符(DPL=3)及选择子
Test3Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL3,D32,>
Test3Stack_Sel = Test3Stack-GDT+RPL3
;测试任务3代码段描述符(DPL=3)及选择子
Test3Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL3,D32,>
Test3Code_Sel = Test3Code-GDT+RPL3
;通用保护故障处理任务的TSS段描述符及选择子
GPTSS Desc <GPTSSLen-1,GPTSSSeg,,AT386TSS,,>
GPTSS_Sel = GPTSS-GDT
;通用保护故障处理任务的堆栈段描述符及选择子
GPStack Desc <GPStackLen-1,GPStackSeg,,ATDW,D32,>
GPStack_Sel = GPStack-GDT
;通用保护故障处理任务的代码段描述符及选择子
GPCode Desc <GPCodeLen-1,GPCodeSeg,,ATCE,D32,>
GPCode_Sel = GPCode-GDT
;其它中断或异常处理程序代码段(一致可读)描述符及选择子
ErrCode Desc <ErrCodeLen-1,ErrCodeSeg,,ATCCOR,D32,>
ErrCode_Sel = ErrCode-GDT
;----------------------------------------------------------------------------
GDNum = ($-EFFGDT)/(SIZE Desc) ;需处理基地址的描述符个数
;----------------------------------------------------------------------------
;指向测试任务的任务门
TestTask Gate <,TestTSS_Sel,,ATTaskGate,>
Test_Sel = TestTask-GDT
;----------------------------------------------------------------------------
GDTLen = $-GDT ;全局描述符表长度
GDTSeg ENDS ;全局描述符表段定义结束
;----------------------------------------------------------------------------
IDTSeg SEGMENT PARA USE16 ;中断描述符表段(16位)
IDT LABEL BYTE ;中断描述符表
REPT 13
Gate <ErrBegin,ErrCode_Sel,,AT386TGate,>
ENDM
Gate <,GPTSS_Sel,,ATTaskGate,> ;通用故障处理程序门描述符
REPT 242
Gate <ErrBegin,ErrCode_Sel,,AT386TGate,>
ENDM
;----------------------------------------------------------------------------
IDTLen = $-IDT
;----------------------------------------------------------------------------
IDTSeg ENDS ;中断描述符表段定义结束
;----------------------------------------------------------------------------
;其它中断或异常处理程序的代码段(一致可读)
;----------------------------------------------------------------------------
ErrCodeSeg SEGMENT PARA USE32
ASSUME CS:ErrCodeSeg
;----------------------------------------------------------------------------
ErrMess DB 'Error!!!'
ErrMessLen = $-ErrMess
;----------------------------------------------------------------------------
ErrBegin PROC FAR
cld
mov ax,ErrCode_Sel
mov ds,ax
lea esi,ErrMess
mov ax,VideoBuf_Sel
mov es,ax
mov edi,1992
mov ecx,ErrMessLen
mov ah,4eh
Err1: lodsb
stosw
loop Err1
jmp $
ErrBegin ENDP
;----------------------------------------------------------------------------
ErrCodeLen = $
ErrCodeSeg ENDS
;----------------------------------------------------------------------------
GPTSSSeg SEGMENT PARA USE16 ;通用保护故障处理任务的TSS
GPTaskSS LABEL BYTE
DD 0 ;任务嵌套时的链接指针
DD 0 ;0级堆栈偏移
DW 0,0 ;0级堆栈选择子
DD 0 ;1级堆栈偏移
DW 0,0 ;1级堆栈选择子
DD 0 ;2级堆栈偏移
DW 0,0 ;2级堆栈选择子
DD 0 ;CR3
DW GPBegin,0 ;EIP
DD 0 ;EFLAGS
DD 0 ;EAX
DD 0 ;ECX
DD 0 ;EDX
DD 0 ;EBX
DD GPStackLen ;ESP
DD 0 ;EBP
DD 0 ;ESI
DD 0 ;EDI
DW VideoBuf_Sel,0 ;ES
DW GPCode_Sel,0 ;CS
DW GPStack_Sel,0 ;SS
DW ToTestTSS_Sel,0 ;DS
DW ToGPTSS_Sel,0 ;FS
DW 0,0 ;GS
DW 0,0 ;LDTR
DW 0 ;调试陷阱标志
DW $+2 ;指向I/O许可位图的偏移
DB 0ffh ;I/O许可位图结束标志
GPTSSLen = $
GPTSSSeg ENDS
;----------------------------------------------------------------------------
GPStackSeg SEGMENT PARA USE32 ;通用保护故障处理任务堆栈段
GPStackLen = 512
DB GPStackLen DUP(0)
GPStackSeg ENDS
;----------------------------------------------------------------------------
;通用保护故障处理程序代码段
;----------------------------------------------------------------------------
GPCodeSeg SEGMENT PARA USE32
ASSUME CS:GPCodeSeg
;----------------------------------------------------------------------------
GPBegin PROC FAR
;在屏幕左上角显示故障点
xor edi,edi
mov ebx,OFFSET TestTaskSS
mov edx,DWORD PTR [ebx].TRCS
call EchoEDX
mov ax,(17h SHL 8)+':'
stosw
mov edx,[ebx].TREIP
call EchoEDX
;演示以便看清故障点
mov ecx,1234567h
loop $
;调整任务链接指针,中止故障任务
mov ebx,OFFSET GPTaskSS
mov ax,DemoTSS_Sel
mov fs:[ebx].TRLink,ax
add esp,4
iretd
jmp GPBegin
GPBegin ENDP
;----------------------------------------------------------------------------
;显示edx内容的子程序
;----------------------------------------------------------------------------
EchoEDX PROC
mov ah,17h
mov ecx,8
EchoEDX1: rol edx,4
mov al,dl
call HToASCII
stosw
loop EchoEDX1
ret
EchoEDX ENDP
;----------------------------------------------------------------------------
;把4位二进制数转换成对应的ASCII码
;----------------------------------------------------------------------------
HToASCII PROC
and al,0fh
add al,90h
daa
adc al,40h
daa
ret
HToASCII ENDP
;----------------------------------------------------------------------------
GPCodeLen = $
GPCodeSeg ENDS
;----------------------------------------------------------------------------
;测试任务的TSS段
TestTSSSeg SEGMENT PARA USE16
TestTaskSS TSS <> ;TSS的固定格式部分
IOMap LABEL BYTE ;I/O许可位图
DB 8 DUP(0ffh) ;端口00h--3fh
DB 11111011b ;端口40h--47h
DB 3 DUP(0ffh) ;端口48h--5fh
DB 11111101b ;端口60h--67h
DB 0 ;端口68h--6fh
DB 0ffh ;I/O许可位图结束标志
TestTSSLen = $
TestTSSSeg ENDS
;----------------------------------------------------------------------------
;测试任务的堆栈段
TestStackSeg SEGMENT PARA USE32
TestStackLen = 1024
DB TestStackLen DUP(0)
TestStackSeg ENDS
;----------------------------------------------------------------------------
;测试任务的代码段
TestCodeSeg SEGMENT PARA USE32
ASSUME CS:TestCodeSeg
;----------------------------------------------------------------------------
Test3Begin PROC FAR
cli ;I/O敏感指令
clts ;特权指令
iretd
jmp Test3Begin
Test3Begin ENDP
;----------------------------------------------------------------------------
TestBegin PROC FAR
mov al,0b6h ;使扬声器发出一长声
out 43h,al
mov al,2
out 42h,al
mov al,34h
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
mov ecx,1234567h
loop $
mov al,ah
out 61h,al
iretd
jmp TestBegin
TestBegin ENDP
;----------------------------------------------------------------------------
TestCodeLen = $
TestCodeSeg ENDS
;----------------------------------------------------------------------------
;演示任务TSS段
DemoTSSSeg SEGMENT PARA USE16
DemoTaskSS TSS <>
DB 0ffh ;I/O许可位图结束字节
DemoTSSLen = $
DemoTSSSeg ENDS
;----------------------------------------------------------------------------
;演示任务的堆栈段
DemoStackSeg SEGMENT PARA USE32
DemoStackLen = 1024
DB DemoStackLen DUP(0)
DemoStackSeg ENDS
;----------------------------------------------------------------------------
;演示任务的代码段
DemoCodeSeg SEGMENT PARA USE32
ASSUME CS:DemoCodeSeg
;----------------------------------------------------------------------------
DemoBegin PROC FAR
mov ax,ToTestTSS_Sel
mov ds,ax
mov ebx,OFFSET TestTaskSS
;把测试任务1的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test1Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test1Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET TestBegin
mov DWORD PTR [ebx].TREFLAG,IOPL1
;通过任务门调用测试任务
CALL32 Test_Sel,0
;把测试任务2的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test2Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test2Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET TestBegin
mov DWORD PTR [ebx].TREFLAG,IOPL1
;通过任务门调用测试任务
CALL32 Test_Sel,0
;把测试任务TSS描述符内的属性置为"可用"
mov ax,ToGDT_Sel
mov fs,ax
mov fs:TestTSS.Attributes,AT386TSS
;把测试任务3的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test3Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test3Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin
mov DWORD PTR [ebx].TREFLAG,IOPL2
;通过任务门调用测试任务
CALL32 Test_Sel,0
;把测试任务TSS描述符内的属性置为"可用"
mov ax,ToGDT_Sel
mov fs,ax
mov fs:TestTSS.Attributes,AT386TSS
;把测试任务4的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test3Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test3Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin
mov DWORD PTR [ebx].TREFLAG,IOPL3
;通过任务门调用测试任务
CALL32 Test_Sel,0
JUMP32 TempCode_Sel,<OFFSET ToDOS>
DemoBegin ENDP
;----------------------------------------------------------------------------
DemoCodeLen = $
DemoCodeSeg ENDS
;----------------------------------------------------------------------------
TempCodeSeg SEGMENT PARA USE16 ;演示任务的临时代码段
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
;置数据段寄存器为空
mov ax,0
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
;置堆栈指针
mov ax,DemoStack_Sel
mov ss,ax
mov esp,DemoStackLen
;置任务寄存器
mov ax,DemoTSS_Sel
ltr ax
;转演示代码段
JUMP16 DemoCode_Sel,DemoBegin
ToDOS: clts
mov ax,Normal_Sel
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr0
and al,11111110b
mov cr0,eax
JUMP16 <SEG Real>,<OFFSET Real>
Virtual ENDP
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RDataSeg SEGMENT PARA USE16 ;实方式数据段
VGDTR PDesc <GDTLen-1,> ;GDT伪描述符
VIDTR PDesc <IDTLen-1,> ;IDT伪描述符
NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值
SPVar DW ? ;用于保存实方式下的SP
SSVar DW ? ;用于保存实方式下的SS
RDataSeg ENDS
;----------------------------------------------------------------------------
RCodeSeg SEGMENT PARA USE16 ;实方式代码段
ASSUME CS:RCodeSeg,DS:RDataSeg
;----------------------------------------------------------------------------
Start PROC
mov ax,RDataSeg
mov ds,ax
cld
call InitGDT ;初始化全局描述符表GDT
call InitIDT ;初始化中断描述符表IDT
lgdt QWORD PTR VGDTR ;装载GDTR
mov SSVar,ss ;保存堆栈指针
mov SPVar,sp
sidt QWORD PTR NORVIDTR ;保存IDTR
cli ;关中断
lidt QWORD PTR VIDTR ;装载IDTR
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <TempCode_Sel>,<OFFSET Virtual>
Real: mov ax,RDataSeg
mov ds,ax
lss sp,DWORD PTR SPVar ;又回到实方式
lidt QWORD PTR NORVIDTR
sti
mov ax,4c00h
int 21h
Start ENDP
;----------------------------------------------------------------------------
InitGDT PROC
push ds
mov ax,GDTSeg
mov ds,ax
mov cx,GDNum
mov si,OFFSET EFFGDT
InitG: mov ax,[si].BaseL
movzx eax,ax
shl eax,4
shld edx,eax,16
mov WORD PTR [si].BaseL,ax
mov BYTE PTR [si].BaseM,dl
mov BYTE PTR [si].BaseH,dh
add si,SIZE Desc
loop InitG
pop ds
mov bx,16
mov ax,GDTSeg
mul bx
mov WORD PTR VGDTR.Base,ax
mov WORD PTR VGDTR.Base+2,dx
ret
InitGDT ENDP
;----------------------------------------------------------------------------
InitIDT PROC
mov bx,16
mov ax,IDTSeg
mul bx
mov WORD PTR VIDTR.Base,ax
mov WORD PTR VIDTR.Base+2,dx
ret
InitIDT ENDP
;----------------------------------------------------------------------------
RCodeSeg ENDS
END Start
| 参考资料 | 书 名 | 出 版 社 | 作 者 |
| 《保护方式下的80386及其编程》 | 清华大学出版社 | 周明德主编 | |
| 《80X86汇编语言程序设计教程》 | 清华大学出版社 | 扬季文主编 |